/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022.
 * Description: Create /proc/fiq_list to show fiq callbacks.
 * Author: yingelin <yingelin@huawei.com>
 * Create: 2022-08-08
 */

#include <linux/proc_fs.h>
#include <linux/hal/fiq_glue.h>

#ifndef CONFIG_X86
#include "fiq_glue_private.h"
#else
#include "../x86/fiq_glue/fiq_glue_private.h"
#endif

static int print_callbacks(struct seq_file *m, void (*print_func)(const char*, ...) __printf(1, 2))
{
	struct fiq_num_node *fiq_node = NULL;
	struct fiq_callback_node *callback_node = NULL;

	if (!m && !print_func) {
		pr_err("[RTOS fiq] print_func should not be NULL\n");
		return -EINVAL;
	}

	/* Queries are only permited after the fiq_priv.entry is initialized */
	if (fiq_priv.entry.next == NULL || fiq_priv.entry.prev == NULL) {
		pr_err("[RTOS fiq] FIQ is not initialized, please call request_fiq at least once\n");
		return -EFAULT;
	}

	/*
	 * if handling fiq, fiq_register_lock is no need because
	 * there is only reading operation in the scene
	 */
	if (!entry_fiq_mode && !mutex_trylock(&fiq_register_lock)) {
		pr_err("[RTOS fiq] FIQ callchain is busy, do it later\n");
		return -EBUSY;
	}

	if (m)
		seq_printf(m, "[fiq callback]\n");
	else
		print_func("[fiq callback]\n");

	list_for_each_entry(fiq_node, &fiq_priv.entry, node) {
		if (m)
			seq_printf(m, "FIQ NUMBER = %u:\n", fiq_node->fiq_num);
		else
			print_func("FIQ NUMBER = %u:\n", fiq_node->fiq_num);

		list_for_each_entry(callback_node, &fiq_node->callback_head, node) {
			if (m)
				seq_printf(m, "%pS\n", callback_node->callback);
			else
				print_func("%pS\n", callback_node->callback);
		}
	}

	if (!entry_fiq_mode)
		mutex_unlock(&fiq_register_lock);

	return 0;
}

int fiq_print_callbacks(void (*print_func)(const char*, ...) __printf(1, 2))
{
	return print_callbacks(NULL, print_func);
}

EXPORT_SYMBOL_NS(fiq_print_callbacks, HW_RTOS_NS);

static int fiq_show(struct seq_file *m, void *v)
{
	print_callbacks(m, NULL);
	return 0;
}

static int fiqstat_open(struct inode *inode, struct file *file)
{
	return single_open(file, fiq_show, PDE_DATA(inode));
}


static const struct proc_ops fiqstat_proc_ops = {
	.proc_open = fiqstat_open,
	.proc_read = seq_read,
	.proc_lseek = seq_lseek,
	.proc_release = single_release,
};

void proc_fiqstat_init(void)
{
	struct proc_dir_entry *proc_entry = proc_create("fiq_list", 0400, NULL, &fiqstat_proc_ops);

	if (!proc_entry)
		pr_err("[RTOS fiq] /proc/fiq_list is not created\n");
}
